package com.alax.interfaces.utils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class SignatureUtils {
    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
    
    /**
     * 生成签名
     * @param params 请求参数
     * @param secretKey 密钥
     * @return 签名
     */
    public static String generateSignature(Map<String, Object> params, String secretKey) throws Exception {
        // 1. 参数排序
        TreeMap<String, Object> sortedParams = new TreeMap<>(params);
        
        // 2. 拼接参数
        String paramStr = sortedParams.entrySet().stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining("&"));
        
        // 3. 使用HMAC-SHA256算法生成签名
        Mac hmacSha256 = Mac.getInstance(HMAC_SHA256_ALGORITHM);
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), HMAC_SHA256_ALGORITHM);
        hmacSha256.init(secretKeySpec);
        
        byte[] signatureBytes = hmacSha256.doFinal(paramStr.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(signatureBytes);
    }
    
    /**
     * 验证签名
     * @param params 请求参数
     * @param signature 待验证的签名
     * @param secretKey 密钥
     * @return 是否验证通过
     */
    public static boolean verifySignature(Map<String, Object> params, String signature, String secretKey) {
        try {
            String calculatedSignature = generateSignature(params, secretKey);
            return calculatedSignature.equals(signature);
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 验证时间戳是否有效（防重放攻击）
     * @param timestamp 请求时间戳
     * @param timeWindow 有效时间窗口（毫秒）
     * @return 是否在有效期内
     */
    public static boolean isTimestampValid(long timestamp, long timeWindow) {
        long currentTime = System.currentTimeMillis();
        return Math.abs(currentTime - timestamp) <= timeWindow;
    }
} 